<?php

/*
	author: d3m
	Calculates the score for each entity
    Sorts the entities based on scores
    Returns an an array with sorted(descending) entities-scores based on scores

	STATUS: Completed and Debugged
	toDO: take into account user's preferences on ranking type

*/
function BL_getRanking( $entity_ids, $weight_list, $ranking_type)
{
	if( count($entity_ids, 0) == 0)
		return BL_GET_RANKING_NO_ENTITIES;

    $i = 0;
    $entities = array();
    foreach ($entity_ids as $entityId)
    {
        $entities[$i] = DB_getEntity($entityId);
        $i++;
    }

	$attr = $entities[0]->GetAttributes();
	if( count($attr, 0) != count($weight_list, 0) )
		return BL_GET_RANKING_ERROR_IN_WEIGHT_LIST;


    $optimisedValues = GetOptimisedValuesOfAttributes($entities);
	//print_r($optimisedValues);

    $i = 0;
    $scores = array();
	//print_r($entities);
    foreach ($entities as $entity)
    {
        $attributes = $entity->GetAttributes();
        $scores[$i] = 0;
        $j = 0;

        foreach ($attributes as $attribute)
        {
            if ($weight_list[$j] != 0)
            {
				if ($attribute->GetType() == "m") // Measureable attribute
                {
					if( $attribute->GetBestValue() == "max" )
					{	/* $optimisedValues[j] concerns the maximum existing value of the specific attribute */
						//$scores[$i] += ($attribute->GetValue()/$optimisedValues[$j]) * $weight_list[$j];
						if ( ($optimisedValues[$j][0] - $optimisedValues[$j][1]) != 0)
							$scores[$i] += (1 - ( abs($attribute->GetValue() - $optimisedValues[$j][0]) / abs($optimisedValues[$j][0] - $optimisedValues[$j][1]) ) ) * $weight_list[$j];
						else
							$scores[$i] += $weight_list[$j];
					}
					elseif( $attribute->GetBestValue() == "min" )
					{
						/* $optimisedValues[j] concerns the minimum existing value of the specific attribute */
						//$scores[$i] += (1 - abs($attribute->GetValue() - $optimisedValues[$j])/ $attribute->GetValue() ) * $weight_list[$j];
                        if ( ($optimisedValues[$j][0] - $optimisedValues[$j][1]) != 0)
							$scores[$i] += (1 - ( abs($attribute->GetValue() - $optimisedValues[$j][1]) / abs($optimisedValues[$j][0] - $optimisedValues[$j][1]) ) ) * $weight_list[$j];
						else
							$scores[$i] += $weight_list[$j];

					}
                    else /* BestValue is close_to(x) */
                    {
                        $x = $attribute->GetCloseToValue();

						//$scores[$i] += ( 1 - abs( ( $x - $attribute->GetValue() )/$x ) ) * $weight_list[$j];
                        $div = max( abs($x - $optimisedValues[$j][0]), abs($x - $optimisedValues[$j][1]) );
                        if ($div == 0) $div = 1; // Bad division by zero!
                        $scores[$i] += ( 1 - ( abs($x - $attribute->GetValue()) / $div ) ) * $weight_list[$j];
					}
                }
				else 
				{/* Quality attribute*/
                    $scores[$i] += $weight_list[$j];
				}
            }
			$j++;
        }
        $i++;
    }

    $result = sortEntitiesScores($scores, $entities);
    return $result;
}

/*
    Status: Completed and Debugged
    author: d3m
	Returns an array for each attribute the max and min value within the entities
*/

function GetOptimisedValuesOfAttributes( $entities )
{
	/* initialization for the comparison */
    $i = 0;
	$attributes = $entities[0]->GetAttributes();
	foreach ( $attributes as $attribute)
    {
		$value = $attribute->GetValue();
		$bestValues[$i][0] = $value;
		$bestValues[$i][1] = $value;

        $i++;
    }

	/* search for max, min of attributes */
    foreach ($entities as $entity)
    {
        $attributes = $entity->GetAttributes();

        $i = 0;
		/* for every attribute get the best [max,min] value within the entities*/

		foreach ( $attributes as $attribute)
        {
			$value = $attribute->GetValue();
			if( $attribute->GetType() == "m" )
            {
				/* Check for max value */
				if( $value > $bestValues[$i][0] )
					$bestValues[$i][0] = $value;

				/* Check for min value */
				if( $value < $bestValues[$i][1] )
					$bestValues[$i][1] = $value;
			}
			else /* non measureable */
            {
				$bestValues[$i][0] = 1;
				$bestValues[$i][1] = 1;
            }

            $i++;
        }
    }

    return $bestValues;
}

/*
    Status: COMPLETED and Debugged

    author: d3m
    Returns an array with sorted(descending) entities-scores based on scores
*/

function sortEntitiesScores($scores, $entities)
{
    arsort($scores);

    /* now sort the entities based on the array keys of scores array (index association is maintained) */
    $keys = array_keys($scores);
    $i = 0;

    $newEntities = array();

    foreach ($keys as $key)
    {
        $newEntities[$i] = $entities[$key];
        $i++;
    }

    $returnArr[0] = $newEntities;
    $returnArr[1] = $scores;

    return $returnArr;
}

/*
    author: basanas, d3m
    Normalises the elements of the array $scores (1st argument) to the value of 100.
*/

function normalizeScores($scores)
{
    $max = max($scores);
    $normScores = Array();

	if ($max != 0)
	{
		foreach ($scores as $key => $score)
		{
			
			$normScores[$key] = ($score / abs($max) ) * 100;
		}
	}
	/*else  zero scoresn no normalization needed */

    return $normScores;
}

?>